Security News
NVD Backlog Tops 20,000 CVEs Awaiting Analysis as NIST Prepares System Updates
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Complete implementation of RFC6902 "JavaScript Object Notation (JSON) Patch"
(including RFC6901 "JavaScript Object Notation (JSON) Pointer"),
for creating and consuming application/json-patch+json
documents.
Also offers "diff" functionality without using Object.observe
.
npm install --save rfc6902
var rfc6902 = require('rfc6902')
rfc6902.createPatch({first: 'Chris'}, {first: 'Chris', last: 'Brown'})
//⇒ [ { op: 'add', path: '/last', value: 'Brown' } ]
var users = [{first: 'Chris', last: 'Brown', age: 20}]
rfc6902.applyPatch(users, [
{op: 'replace', path: '/0/age', value: 21},
{op: 'add', path: '/-', value: {first: 'Raphael', age: 37}},
])
The applyPatch
function returns [null, null]
,
indicating there were two patches, both applied successfully.
The users
variable is modified in place; evaluate it to examine the end result:
users
//⇒ [ { first: 'Chris', last: 'Brown', age: 21 },
// { first: 'Raphael', age: 37 } ]
In ES6 syntax:
import {applyPatch, createPatch} from 'rfc6902'
Using TypeScript annotations for clarity:
applyPatch(object: any, patch: Operation[]): Array<Error | null>
The operations in patch
are applied to object
in-place.
Returns a list of results as long as the given patch
.
If all operations were successful, each item in the returned list will be null
.
If any of them failed, the corresponding item in the returned list will be an Error instance
with descriptive .name
and .message
properties.
createPatch(input: any, output: any, diff?: VoidableDiff): Operation[]
Returns a list of operations (a JSON Patch) of the required operations to make input
equal to output
.
In most cases, there is more than one way to transform an object into another.
This method is more efficient than wholesale replacement,
but does not always provide the optimal list of patches.
It uses a simple Levenshtein-type implementation with Arrays,
but it doesn't try for anything much smarter than that,
so it's limited to remove
, add
, and replace
operations.
The optional diff
argument allows the user to specify a partial function
that's called before the built-in diffAny
function.
For example, to avoid recursing into instances of a custom class, say, MyObject
:
function myDiff(input: any, output: any, ptr: Pointer) {
if ((input instanceof MyObject || output instanceof MyObject) && input != output) {
return [{op: 'replace', path: ptr.toString(), value: output}]
}
}
const my_patch = createPatch(input, output, myDiff)
This will short-circuit on encountering an instance of MyObject
, but otherwise recurse as usual.
Operation
interface Operation {
op: 'add' | 'remove' | 'replace' | 'move' | 'copy' | 'test'
from?: string
path?: string
value?: string
}
Different operations use different combinations of from
/ value
;
see JSON Patch (RFC6902) below.
Simple web app using the browser-compiled version of the code.
If you've ever implemented Levenshtein's algorithm,
or played tricks with git rebase
to get a reasonable sequence of commits,
you'll realize that computing diffs is rarely deterministic.
E.g., to transform the string ab
→ bc
, you could:
a
(⇒ b
)c
(⇒ bc
)Or...
b
with c
(⇒ ac
)a
with b
(⇒ bc
)Both consist of two operations, so either one is a valid solution.
Applying json-patch
documents is much easier than generating them,
which might explain why, when I started this project,
there were more than five patch-applying RFC6902 implementations in NPM,
but none for generating a patch from two distinct objects.
(There was one that used Object.observe()
, which only works when you're the one making the changes,
and only as long as Object.observe()
hasn't been deprecated, which it has.)
So when comparing your data objects, you'll want to ensure that the patches it generates meet your needs. The algorithm used by this library is not optimal, but it's more efficient than the strategy of wholesale replacing everything that's not an exact match.
Of course, this only applies to generating the patches. Applying them is deterministic and unambiguously specified by RFC6902.
The RFC is a quick and easy read, but here's the gist:
/reference-token
parts.
reference-token
bits are usually Object keys,
but may also be (decimal) numerals, to indicate array indices.E.g., consider the NPM registry:
{
"_updated": 1417985649051,
"flickr-with-uploads": {
"name": "flickr-with-uploads",
"description": "Flickr API with OAuth 1.0A and uploads",
"repository": {
"type": "git",
"url": "git://github.com/chbrown/flickr-with-uploads.git"
},
"homepage": "https://github.com/chbrown/flickr-with-uploads",
"keywords": [
"flickr",
"api",
"backup"
],
...
},
...
}
/_updated
: this selects the value of that key, which is just a number: 1417985649051
/flickr-with-uploads
: This selects the entire object:
{
"name": "flickr-with-uploads",
"description": "Flickr API with OAuth 1.0A and uploads",
"repository": {
"type": "git",
"url": "git://github.com/chbrown/flickr-with-uploads.git"
},
"homepage": "https://github.com/chbrown/flickr-with-uploads",
"keywords": [
"flickr",
"api",
"backup"
],
...
}
/flickr-with-uploads/name
: this effectively applies the /name
pointer to the result of the previous item,
which selects the string, "flickr-with-uploads"
./flickr-with-uploads/keywords/1
: Array indices start at 0,
so this selects the second item from the keywords
array, namely, "api"
.Rules:
/
in the desired key should be replaced by the escape sequence, ~1
.~
should be replaced by the other escape sequence, ~0
.
This allows keys containing the literal string ~1
(which is especially cruel)
to be referenced by a JSON pointer (e.g., /~01
should return true
when applied to the object {"~1":true}
).This project implements JSON Pointer functionality in rfc6902/pointer
; e.g.:
const {Pointer} = require('rfc6902/pointer')
const repository = {
contributors: ['chbrown', 'diachedelic', 'nathanrobinson', 'kbiedrzycki', 'stefanmaric']
}
const pointer = Pointer.fromJSON('/contributors/0')
//⇒ Pointer { tokens: [ '', 'contributors', '0' ] }
pointer.get(repository)
//⇒ 'chbrown'
The RFC is only 18 pages long, but here are the basics:
A JSON Patch document is a JSON document such that:
application/json-patch+json
.json-patch
op
, with one of the following six values,
and an operator-specific set of other keys.
add
: Insert the given value
at path
. Or replace it, if it already exists.
If the parent of the intended target does not exist, produce an error.
If the final reference-token of path
is "-
", and the parent is an array, append value
to it.
path
: JSON Pointervalue
: JSON objectremove
: Remove the value at path
. Produces an error if it does not exist.
If path
refers to an element within an array,
splice it out so that subsequent elements fill in the gap (decrementing the length of the array).
path
: JSON Pointerreplace
: Replace the current value at path
with value
.
It's exactly the same as performing a remove
operation and then an add
operation on the same path,
since there must be a pre-existing value.
path
: JSON Pointervalue
: JSON objectmove
: Remove the value at from
, and set path
to that value.
There must be a value at from
, but not necessarily at path
;
it's the same as performing a remove
operation, and then an add
operation, but on different paths.
from
: JSON Pointerpath
: JSON Pointercopy
: Get the value at from
and set path
to that value.
Same as move
, but doesn't remove the original value.
from
: JSON Pointerpath
: JSON Pointertest
: Check that the value at path
is equal to value
.
If it is not, the entire patch is considered to be a failure.
path
: JSON Pointervalue
: JSON objectCopyright 2014-2019 Christopher Brown. MIT Licensed.
FAQs
Complete implementation of RFC6902 (patch and diff)
We found that rfc6902 demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Security News
Research
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.
Security News
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.